﻿using System;
using System.Collections.Generic;
using NUnit.Framework;
using System.Reflection;
using TestDoc;

namespace Specs_For_DllParser
{
    [TestFixture]
    public class When_Parsing_Library
    {
        public string PublicFieldForTests;

        private Assembly _assembly;

        #region Setup and Teardown methods
        [TestFixtureSetUp]
        public void BeforeSuite()
        {
            _assembly = Assembly.GetExecutingAssembly();

        }

        [TestFixtureTearDown]
        public void AfterSuite()
        {

        }

        [SetUp]
        public void BeforeEachTest()
        {

        }

        [TearDown]
        public void AfterEachTest()
        {

        }
        #endregion Setup and teardown methods

        [Test]
        public void CreatingParserShouldReturnInstance()
        {
            var parser = new TestParser(_assembly);

            // Asserts
            Assert.IsNotNull(parser, "parser instance");
        }

        [Test]
        public void ShouldReturnInstanceOfList()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            var methods = parser.GetTests();

            // Assert
            Assert.IsNotNull(methods);
            Assert.IsInstanceOf(typeof(IList<MethodInfo[]>), methods, "Return type");
        }

        [Test]
        public void ShouldReturnNonZeroList()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            ICollection<MethodInfo[]> methods = parser.GetTests();

            // Assert
            Assert.IsFalse(methods.Count == 0, "Methods");
        }

        [Test]
        public void ShouldNotIncludeFields()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            ICollection<MethodInfo[]> methods = parser.GetTests();

            // Assert
            bool found = found = Contains(methods, "PublicFieldForTests");

            Assert.IsFalse(found);

        }

        [Test]
        public void ShouldOnlyIncludeNunitMethods()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            ICollection<MethodInfo[]> methods = parser.GetTests();

            // Assert
            bool found = Contains(methods, "Contains");

            Assert.IsFalse(found, "Non tests");

        }

        [Test]
        public void ShouldNotContainNullElements()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            ICollection<MethodInfo[]> methods = parser.GetTests();

            // Assert
            bool found = ContainsNulls(methods);
            Assert.IsFalse(found, "Nulls");

        }
        [Test]
        public void Should_Include_All_Types()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            var methods = parser.GetTests();

            // Assert
            Assert.IsTrue(methods.Count >1, "Missing types");
        }

        [Test]
        public void Component_With_No_Tests_Should_Return_Nothing()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            IList<MethodInfo[]> types = parser.GetTests();
                
            // Assert
            bool foundZero = false;                
            foreach(MethodInfo[] methods in types)
            {
                if(methods.Length == 0)
                {
                    foundZero = true;
                }
            }

            Assert.AreEqual(false, foundZero, "returned methods");

        }

        [Test]
        [Description("Discovery test")]
        [Ignore]
        public void HowToInspectMethodBody()
        {
            // Arrange
            var parser = new TestParser(_assembly);

            // Act
            IList<MethodInfo[]> methods = parser.GetTests();
            MethodInfo m = methods[2][6];
            MethodBody body = m.GetMethodBody();
           
        }

        #region Private methods
        public bool Contains(IEnumerable<MethodInfo[]> methods, string find)
        {
            bool found = false;

            foreach (var type in methods)
            {
                foreach (var method in type)
                {
                    if (method != null)
                    {
                        if (method.Name == find)
                        {
                            found = true;
                        }
                    }
                }
            }
            return found;
        }


        public bool ContainsNulls(IEnumerable<MethodInfo[]> methods)
        {
            bool found = false;

            foreach (var type in methods)
            {
                foreach (var method in type)
                {
                    if (method == null)
                    {
                        found = true;
                    }
                }
            }
            return found;
        }


        public long CountItems(ICollection<MethodInfo[]> methods)
        {
            long count = 0;

            foreach (var infose in methods)
            {
                count += infose.Length;
            }

            return count;
        }

        public long GetListOfTestMethodsInSuite()
        {
            Type[] types = _assembly.GetTypes();
            long methodCount = 0;

            foreach (var type in types)
            {
                MethodInfo[] methodInfos = type.GetMethods();
                methodCount += methodInfos.Length;
            }

            return methodCount;
        }
            
        #endregion private methods
    }
}